###################################################################
#
#  LimitChan.tcl v1.0-beta
#  Written by John Hall
#
#  Script Author Contact Information
#  -----------------------------------------------------------------
#  
#  This script was written by John Hall. To contact, write to
#  john@kire.net or irc.abovenet.org and join #abovenet. This
#  version of limitchan.tcl is valid as of June 18th, 2002.
#
###################################################################

###################################################################
#
#  Notes
#
#  Thanks for downloading LimitChan.tcl! Yes, this is another
#  TCL to limit the number of people in your channel to avoid
#  mass-flooding by clones or something, but I wrote this one
#  for a little different reason. I noticed that all of these
#  TCLs have a list of static channels on compile time, and all of
#  the variables for the channels were also static. I figured that
#  someone might like to have a version of it that could be put
#  on any channel on the bot without having to edit variables, but
#  just letting the channel owner set it themselves. So, here's
#  the TCL; enjoy!
#
###################################################################

###################################################################
#
#  Important
#
#  This TCL is beta software. Its not guaranteed to operate
#  correctly under any conditions and may cause harm to your
#  system. By using this TCL, you accept full responsibility for
#  anything that this TCL may produce.
#
###################################################################

###################################################################
#
#  Options
#
#  Basically, all you need to do here, if you wish, is setup some
#  general factors for the channels. If you don't care to set up
#  these variables, feel free not to mess with them and the TCL
#  will compensate with the default settings. You will need to
#  uncomment them to use them; just remove the # before them.
#
###################################################################

# Default increment for channels
# This tells by how much a channel's limit should be increased if
# the channel is using limiting.
#
# set default_increment 5

# Default mode for channels
# Should all channels use limiting by default or not?
# 1 = yes; 0 = no
#
set default_uselimiting 0

# Default security setting for channels
# Place full security on every channel or just one way? By placing
# full security, the bot will mode the channel according to the
# user count and always make sure its only the default increment
# off. If you use one-way, it will only increase and not check
# for decreases. Valid options are "full" or "one-way"
#
# set default_security "full"

# Default check time for all channels
# Set this to how long you want the TCL to wait to check for a
# need for limiting in a channel by default. This is set in
# minutes.
#
# set default_check 1

# TCL verbose setting
# If you want the TCL to report information about what its doing
# to the log of the bot, then enable this. Its extremely useful
# in determining problems if they do arise.
# 1 = yes; 0 = no
#
# set default_verbose 1

###################################################################
#
#  End of Settings
#
#  Alrighty, there's not really anything more for you to fiddle
#  with in this TCL, unless you are one of those freaks who
#  absolutely has to change the code in every TCL they use just to
#  feel like they are worth something (lol, I do that, but not
#  because I don't think I'm not worth anything, I just don't like
#  other people's stuff usually). Enjoy!
#
###################################################################

# I don't see a point in screwing with this, but do as you please.
set limitchan_version "1.0-beta"

# This is the name of the memory system for the TCL. If you want to
# change this, change it the first time you run it and never again.
# Each time you change this, the bot will make a new memory system
# and you will loose all your settings unless you change it back.
set limitchan_memname "lcmsu01"

# Check to see if the defaults have been modified
if {(![info exists default_increment]) || ($default_increment == "") || ($default_increment < 1)} {
  set default_increment 5
}
if {(![info exists default_uselimiting]) || ($default_uselimiting == "") || ($default_uselimiting < 0)} {
  set default_uselimiting 1
}
if {(![info exists default_security]) || ($default_security == "")} {
  set default_security "full"
} else {
  if {([string tolower $default_security] != "full") && ([string tolower $default_security] != "one-way")} {
    set default_security "full"
  }
  if {$default_security != [string tolower $default_security]} {
    set default_security [string tolower $default_security]
  }
}
if {(![info exists default_check]) || ($default_check == "") || ($default_check < 0)} {
  set default_check 1
} elseif {$default_check < 2} {
  set default_check 1
}
if {(![info exists default_verbose]) || ($default_verbose == "") || ($default_verbose < 0)} {
  set default_verbose 1
} else {
}
if {(![info exists limitchan_version]) || ($limitchan_version == "")} {
  set limitchan_version "unknown"
}
if {(![info exists limitchan_memname]) || ($limitchan_memname == "")} {
  set limitchan_memname "lcmsu01"
} elseif {[string length $limitchan_memname] > 9} {
  set limitchan_memname "[string left $limitchan_memname 9]"
}

if {[string length $nick] > 2} {
  set lc_shortcut [string tolower "![string index $nick 0][string index $nick [expr [string length $nick] - 1]]"]
} else {
  set lc_shortcut [string tolower "!$nick"]
}

bind pub - shortcut lc:dosc

proc lc:dosc {nick host handle chan arg} {
  global lc_shortcut
  putquick "NOTICE $nick :$lc_shortcut"
}

foreach timr [timers] {
  if {[lindex $timr 1] == "lc:checkforlimits"} {
    killtimer [lindex $timr 2]
  }
}

proc lc:putlog {text} {
  global default_verbose
  if {$default_verbose == 1} {
    putlog "$text"
  }
}

proc lc:checkcore {} {
  global limitchan_memname
  if {![validuser $limitchan_memname]} {
    lc:addcore
    lc:putlog "Couldn't find core memory system for LimitChan.tcl, so it was added..."
  } else {
    set mnote [getuser $limitchan_memname XTRA "mversys"]
    if {$mnote != "lcms"} {
      lc:putlog "Couldn't properly verify the core memory system for LimitChan.tcl, so it will be automatically deleted and readded..."
      lc:remcore
      lc:addcore
    }
  }
}

proc lc:addcore {} {
  global limitchan_memname
  if {![validuser $limitchan_memname]} {
    set mhost "*!*@256.256.256.256"
    set mpass "[rand 123456789][rand 123456789]"
    set mpass "[encrypt [rand 123456789] $mpass]"
    set maddr "256.256.256.256:[rand 63533]"
    set mcmnt "Memory system for LimitChan.tcl - DO NOT REMOVE"
    set mnote "lcms"
    addbot $limitchan_memname $maddr
    setuser $limitchan_memname HOSTS $mhost
    setuser $limitchan_memname PASS $mpass
    setuser $limitchan_memname COMMENT $mcmnt
    setuser $limitchan_memname XTRA "mversys" $mnote
  }
}

proc lc:remcore {} {
  global limitchan_memname
  if {[validuser $limitchan_memname]} {
    deluser $limitchan_memname
  }
}

proc lc:dolimit {chan chanincr issecure} {
  if {![botonchan $chan]} {
    return 0
  }
  set chanmodes [getchanmode $chan]
  set chanmchar [lindex $chanmodes 0]
  set x 0
  set place 0
  set chanlimit 0
  set newlimit 0
  while {$x < [string length $chanmchar]} {
    set chr [string index $chanmchar $x]
    if {$chr == "k"} {
      incr place
      continue
    }
    if {$chr == "l"} {
      incr place
      set chanlimit [lindex $chanmodes $place]
      break
    }
    incr x
  }
  set chanucount [llength [chanlist $chan]]
  if {$chanlimit > [expr $chanucount + $chanincr]} {
    if {$issecure} {
      set limitdiff [expr $chanlimit - [expr $chanucount + $chanincr]]
      set newlimit [expr $chanlimit - $limitdiff]
    }
  } elseif {$chanlimit <  [expr $chanucount + $chanincr]} {
    set limitdiff [expr [expr $chanucount + $chanincr] - $chanlimit]
    set newlimit [expr $chanlimit + $limitdiff]
  }
  if {$newlimit > 0} {
    pushmode $chan +l $newlimit
  } else {
  }
}

proc lc:checkchan {chan} {
  global default_increment default_uselimiting default_security default_check limitchan_memname
  lc:checkcore
  set increment [getuser $limitchan_memname XTRA "$chan.increment"]
  set uselimiting [getuser $limitchan_memname XTRA "$chan.uselimiting"]
  set security [getuser $limitchan_memname XTRA "$chan.security"]
  set check [getuser $limitchan_memname XTRA "$chan.check"]
  set lastcheck [getuser $limitchan_memname XTRA "$chan.lastcheck"]
  if {($increment == "") || ($increment < 1)} {
    setuser $limitchan_memname XTRA "$chan.increment" $default_increment
  }
  if {($uselimiting == "") || ($uselimiting < 0)} {
    setuser $limitchan_memname XTRA "$chan.uselimiting" $default_uselimiting
  }
  if {($security == "")} {
    setuser $limitchan_memname XTRA "$chan.security" $default_security
  } elseif {($security != "full") && ($security != "one-way")} {
    setuser $limitchan_memname XTRA "$chan.security" $default_security
  }
  if {($check == "") || ($check < 2)} {
    setuser $limitchan_memname XTRA "$chan.check" $default_check
  }
  if {($lastcheck == "") || ($lastcheck < 0)} {
    setuser $limitchan_memname XTRA "$chan.lastcheck" 1
  }
}

proc lc:checkforlimits {} {
  global limitchan_memname
  set chanlist [channels]
  foreach chan $chanlist {
    lc:checkchan $chan
    set increment [getuser $limitchan_memname XTRA "$chan.increment"]
    set uselimiting [getuser $limitchan_memname XTRA "$chan.uselimiting"]
    set security [getuser $limitchan_memname XTRA "$chan.security"]
    set check [getuser $limitchan_memname XTRA "$chan.check"]
    set lastcheck [getuser $limitchan_memname XTRA "$chan.lastcheck"]
    if {!$uselimiting} {
      continue
    } else {
      set timesincecheck [expr $lastcheck - $check]
      if {$timesincecheck == 0} {
        if {$security == "full"} {
          set issecure 1
        } else {
          set issecure 0
        }
        lc:dolimit $chan $increment $issecure
        setuser $limitchan_memname XTRA "$chan.lastcheck" 1
      } else {
        set newlastcheck [expr $lastcheck + 1]
        setuser $limitchan_memname XTRA "$chan.lastcheck" $newlastcheck
      }
    }
  }
  timer 1 lc:checkforlimits
}

bind pub - $lc_shortcut lc:pubcommand

proc lc:pubcommand {nick host handle chan arg} {
  global limitchan_memname
  if {$arg == ""} {
    return 0
  }
  set params [string tolower $arg]
  set command [lindex $params 0]
  set params [lrange $params 1 end]
  switch -exact -- $command {
    set {
      set subcommand [lindex $params 0]
      set params [lrange $params 1 end]
      if {$subcommand == ""} {
        return 0
      }
      if {(![matchattr $handle |n $chan]) && (![matchattr $handle n])} {
        return 0
      }
      switch -exact -- $subcommand {
        limiting {
          set option [lindex $params 0]
          set params [lrange $params 1 end]
          if {$option == ""} {
            return 0
          }
          switch -exact -- $option {
            on {
              if {[getuser $limitchan_memname XTRA "$chan.uselimiting"] != 1} {
                setuser $limitchan_memname XTRA "$chan.uselimiting" 1
                putquick "NOTICE $nick :Limiting is now \002active\002 on $chan."
              } else {
                putquick "NOTICE $nick :Limiting is currently \002active\002 in $chan."
              }
            }
            off {
              if {[getuser $limitchan_memname XTRA "$chan.uselimiting"] != 0} {
                setuser $limitchan_memname XTRA "$chan.uselimiting" 0
                putquick "NOTICE $nick :Limiting is now \002inactive\002 on $chan."
              } else {
                putquick "NOTICE $nick :Limiting is currently \002inactive\002 in $chan."
              }
            }
          }
        }
        check {
          set newcheck [lindex $params 0]
          if {$newcheck == ""} {
            return 0
          }
          if {$newcheck < 1} {
            putquick "NOTICE $nick :Your check time must be at least 1 minute in order for limiting to be active."
            return 0
          }
          setuser $limitchan_memname XTRA "$chan.check" $newcheck
          putquick "NOTICE $nick :Check time for limiting on $chan is now \002$newcheck\002."
        }
        increment {
          set newincrement [lindex $params 0]
          if {$newincrement == ""} {
            return 0
          }
          if {$newincrement < 1} {
            putquick "NOTICE $nick :Your increment must be at least 1 in order for limiting to be active."
            return 0
          }
          setuser $limitchan_memname XTRA "$chan.increment" $newincrement
          putquick "NOTICE $nick :Increment for limiting on $chan is now \002$newincrement\002."
        }
        security {
          set newsecurity [lindex $params 0]
          if {$newsecurity == ""} {
            return 0
          }
          if {($newsecurity != "full") && ($newsecurity != "one-way")} {
            putquick "NOTICE $nick :You must specify either \002full\002 or \002one-way\002 security for limiting."
            return 0
          }
          setuser $limitchan_memname XTRA "$chan.security" $newsecurity
          putquick "NOTICE $nick :Security for limiting on $chan is now \002$newsecurity\002."
        }
      }
    }
    help {
      set subcommand [lindex $params 0]
      set params [lrange $params 1 end]
      if {$subcommand == ""} {
        putquick "NOTICE $nick :\002Help\002 for LimitChan.tcl - Written by John Hall"
        putquick "NOTICE $nick :-----------------------------------------------------------------"
        if {([matchattr $handle |n $chan]) || ([matchattr $handle +n])} {
          putquick "NOTICE $nick :\002Channel Masters\002:"
          putquick "NOTICE $nick :  set <command>"
          putquick "NOTICE $nick :  This will allow you to alter the settings for the limit TCL"
          putquick "NOTICE $nick :  in your channel only."
          putquick "NOTICE $nick : "
          putquick "NOTICE $nick :  \002Valid Settings\002:"
          putquick "NOTICE $nick :    limiting - turns limit \002on\002 or \002off\002"
          putquick "NOTICE $nick :    check - sets, in minutes, how often the bot checks the"
          putquick "NOTICE $nick :      limit on the channel."
          putquick "NOTICE $nick :    increment - sets by how much the limit should be above"
          putquick "NOTICE $nick :      the number of users in the channel."
          putquick "NOTICE $nick :    security - sets the type of limit security."
          putquick "NOTICE $nick :  "
        }
        putquick "NOTICE $nick :\002Public\002:"
        putquick "NOTICE $nick :  help <parameters>"
        putquick "NOTICE $nick :  This will allow you to find out information about commands."
        putquick "NOTICE $nick :   "
        putquick "NOTICE $nick :  limitinfo"
        putquick "NOTICE $nick :  This will allow you to see the current information that the"
        putquick "NOTICE $nick :  limit system is operating with on a channel."
      }
      switch -exact -- $subcommand {
        set {
          set option [lindex $params 0]
          set params [lrange $params 1 end]
          if {$option == ""} {
            putquick "NOTICE $nick :\002Help\002 for LimitChan.tcl - Written by John Hall"
            putquick "NOTICE $nick :-----------------------------------------------------------------"
            putquick "NOTICE $nick :  set <command>"
            putquick "NOTICE $nick :  This will allow you to alter the settings for the limit TCL"
            putquick "NOTICE $nick :  in your channel only."
            putquick "NOTICE $nick : "
            putquick "NOTICE $nick :  \002Valid Settings\002:"
            putquick "NOTICE $nick :    limiting - turns limit \002on\002 or \002off\002"
            putquick "NOTICE $nick :    check - sets, in minutes, how often the bot checks the"
            putquick "NOTICE $nick :      limit on the channel."
            putquick "NOTICE $nick :    increment - sets by how much the limit should be above"
            putquick "NOTICE $nick :      the number of users in the channel."
            putquick "NOTICE $nick :    security - sets the type of limit security."
          }
          switch -exact -- $option {
            limiting {
              putquick "NOTICE $nick :\002Help\002 for LimitChan.tcl - Written by John Hall"
              putquick "NOTICE $nick :-----------------------------------------------------------------"
              putquick "NOTICE $nick :  set limiting <on | off>"
              putquick "NOTICE $nick :  This will turn limiting on or off in a channel."
            }
            check {
              putquick "NOTICE $nick :\002Help\002 for LimitChan.tcl - Written by John Hall"
              putquick "NOTICE $nick :-----------------------------------------------------------------"
              putquick "NOTICE $nick :  set check <minutes>"
              putquick "NOTICE $nick :  This will set the number of minutes between each check for the"
              putquick "NOTICE $nick :  limit in a channel."
            }
            increment {
              putquick "NOTICE $nick :\002Help\002 for LimitChan.tcl - Written by John Hall"
              putquick "NOTICE $nick :-----------------------------------------------------------------"
              putquick "NOTICE $nick :  set increment <number>"
              putquick "NOTICE $nick :  This will set the number that the limit will be above the user"
              putquick "NOTICE $nick :  count in a channel."
            }
            security {
              putquick "NOTICE $nick :\002Help\002 for LimitChan.tcl - Written by John Hall"
              putquick "NOTICE $nick :-----------------------------------------------------------------"
              putquick "NOTICE $nick :  set security <full | one-way>"
              putquick "NOTICE $nick :  This will set the type of security that limiting will use in a"
              putquick "NOTICE $nick :  channel."
              putquick "NOTICE $nick : "
              putquick "NOTICE $nick :  \002Valid Settings\002:"
              putquick "NOTICE $nick :    full - will make limiting maintain the increment above the"
              putquick "NOTICE $nick :      user count strictly (increases and decreases limit)."
              putquick "NOTICE $nick :    one-way - will make limiting only increase the limit above"
              putquick "NOTICE $nick :      the user count."
            }
          }
        }
      }
    }
    limitinfo {
      set increment [getuser $limitchan_memname XTRA "$chan.increment"]
      set uselimiting [getuser $limitchan_memname XTRA "$chan.uselimiting"]
      set security [getuser $limitchan_memname XTRA "$chan.security"]
      set check [getuser $limitchan_memname XTRA "$chan.check"]
      if {!$uselimiting} {
        putquick "NOTICE $nick :Limiting on $chan is currently \002inactive\002."
        return 0
      }
      putquick "NOTICE $nick :Limiting information for \002$chan\002:"
      putquick "NOTICE $nick :  \002Increment\002: $increment"
      putquick "NOTICE $nick :  \002Security Type\002: $security"
      if {$check > 1} {
        set extension "s"
      } else {
        set extension ""
      }
      putquick "NOTICE $nick :  \002Check Time\002: $check$extension"
      putquick "NOTICE $nick :End of Limiting information."
    }
  }
}

timer 1 lc:checkforlimits
putlog "Loaded LimitChan.tcl - Written by John Hall"
